#    Tichy
#
#    copyright 2008 Guillaume Chereau (charlie137@gmail.com)
#
#    This file is part of Tichy.
#
#    Tichy is free software: you can redistribute it and/or modify it
#    under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Tichy is distributed in the hope that it will be useful, but
#    WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Tichy.  If not, see <http://www.gnu.org/licenses/>.


"""Persistance module"""

# TODO: turn the save and load methods into a `Tasklet`. Saving into a
#       file can take a lot of time.

import os
import yaml

import logging
LOGGER = logging.getLogger('persistance')


class Persistance(object):
    """Use this class to save and load data from file

    All the data will be placed into ~/.tichy directory. They are
    stored using yaml format, but we could modify this cause the
    plugins are not suppoed to read the file directly.
    """

    base_path = os.path.expanduser('~/.tichy/')

    def __init__(self, cls, name):
        self.cls = cls
        self.name = name
        self.dir = os.path.join(self.base_path, str(self.name))
        if not os.path.exists(self.dir):
            os.makedirs(self.dir)

    def _path(self, name):
        return os.path.join(self.dir, '%s.yaml' % name)

    def _open(self, name, mode="r"):
        assert isinstance(name, basestring)
        return open(self._path(name), mode)

    def _remove(self, name):
        os.remove(self._path(name))

    def keys(self):
        ret = []
        for name in os.listdir(self.dir):
            if name.endswith('.yaml'):
                ret.append(name[:-len('.yaml')])
        return ret

    def save(self, obj):
        LOGGER.debug("save %s", obj)
        assert isinstance(obj, self.cls)
        data = obj.serialize()
        file = self._open(unicode(obj.id), 'w')
        file.write(yaml.safe_dump(data, default_flow_style=False))

    def load(self, name):
        file = self._open(name)
        data = yaml.safe_load(file)
        return self.cls.unserialize(data)

    def load_all(self):
        ret = []
        for key in self.keys():
            try:
                ret.append(self.load(key))
            except Exception, ex:
                LOGGER.error("can not load '%s' : %s", key, ex)
        return ret

    def add(self, obj):
        self.save(obj)

        def on_modified(obj):
            self.save(obj)
        obj.connect('modified', on_modified)
        # We keep a ref to the id of the object in case it changes
        obj.__id = obj.id.value

        def on_destroyed(obj):
            LOGGER.debug("remove %s", obj.__id)
            self._remove(obj.__id)
        obj.connect('destroyed', on_destroyed)

        def on_renamed(_, obj):
            LOGGER.debug("rename from %s to %s", obj.__id, obj.id)
            self._remove(obj.__id)
            obj.__id = obj.id.value
        obj.id.connect('modified', on_renamed, obj)
